package clock.socoolby.com.clock.widget.spirit;

import android.text.TextUtils;
import android.util.Log;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.Vector3;
import com.esotericsoftware.spine.AnimationState;
import com.esotericsoftware.spine.AnimationStateData;
import com.esotericsoftware.spine.Skeleton;
import com.esotericsoftware.spine.SkeletonBounds;
import com.esotericsoftware.spine.SkeletonData;
import com.esotericsoftware.spine.SkeletonJson;
import com.esotericsoftware.spine.SkeletonRenderer;
import com.esotericsoftware.spine.SkeletonRendererDebug;
import com.esotericsoftware.spine.Slot;
import com.esotericsoftware.spine.attachments.Attachment;

public  abstract class AbstractLibgdxSpineEffectView implements ApplicationListener {
    public static final String TAG = AbstractLibgdxSpineEffectView.class.getSimpleName();
    public static boolean openDEBUGLog = false;
    protected SkeletonData skeletonData;
    protected AnimationStateData stateData;
    protected SkeletonBounds skeletonBounds;

    //文件所在
    //protected FileHandle extureFile,jsonFile;

    //基础绘制资源
    protected  SpriteBatch mBatch;
    //	Asset资源加载管理
    protected AssetManager mAssetManager = new AssetManager();
    protected int mWidth = 0;
    protected OrthographicCamera camera;
    protected SpriteBatch batch;
    protected SkeletonRenderer renderer;
    protected SkeletonRendererDebug debugRenderer;
    protected TextureAtlas atlas;
    protected Skeleton skeleton;
    protected SkeletonBounds bounds;
    protected AnimationState state;
    protected float x=0;
    protected float y=0;
    protected boolean forceOver = false;
    protected boolean m_candraw = true;
    protected volatile boolean loadingAnimate = true;
    protected ActionEnum befAction=null;

    protected boolean flipXAble =true;

    public AbstractLibgdxSpineEffectView(boolean flipXAble) {
        this.flipXAble = flipXAble;
    }

    public void forceOver() {

        if (openDEBUGLog)
            timber.log.Timber.d("forceOver");

        forceOver = true;

//		缓冲50ms，解决退出时绘制闪动的问题
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void closeforceOver() {

        if (openDEBUGLog)
            timber.log.Timber.d("closeforceOver");

        forceOver = false;

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public abstract void setAction(ActionEnum action);

    public void setClockState(ClockStateEnum clockState){
        switch (clockState){
            case NORMAL:
            case COUNTING:
            case COUNTING_DOWN:
                setAction(ActionEnum.IDLE);
                break;
            case HANDUP:
            case ALTER:
                setAction(ActionEnum.JUMP);
                break;
            case HOUR_ANIMATION:
                setAction(ActionEnum.WALK);
                break;
        }
    }

    public void setEmoji(EmojiEnum emoji){

    }

    public void setPosition(float x, float y){
        this.x=x;
        this.y=y;
        if(skeleton!=null) {
            final Vector3 point=new Vector3();
            camera.unproject(point.set(x, y, 0));
            skeleton.setPosition(point.x, point.y);
            if(flipXAble)
              if(x>mWidth/2)
                  skeleton.setScaleX(-1);
              else
                  skeleton.setScaleX(1);
        }
    }

    @Override
    public void create() {

        if (openDEBUGLog)
            timber.log.Timber.d("create");

        mBatch = new SpriteBatch();

        mWidth = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? Gdx.graphics.getHeight() : Gdx.graphics.getWidth();

        //放置 start 方法

        camera = new OrthographicCamera();
        batch = new SpriteBatch();
        renderer = new SkeletonRenderer();
        renderer.setPremultipliedAlpha(true); // PMA results in correct blending without outlines.
        debugRenderer = new SkeletonRendererDebug();
        debugRenderer.setBoundingBoxes(true);
        debugRenderer.setRegionAttachments(true);

        skeletonBounds=new SkeletonBounds();
/*
*		libgdx资源加载必须在create所在线程执行，如果此步骤耗时过程可以考虑使用AssetManager的方式加载
* */
        atlas = new TextureAtlas(getExtureFile());
/*
*		spine动画加载数据过大，耗时过长，可以移动到子线程中执行
* */
        new Thread(new Runnable() {
            @Override
            public void run() {
                SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless.
                json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine.
                skeletonData = json.readSkeletonData(getJsonFile());
                skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).

                skeleton.setPosition(Gdx.graphics.getWidth()/2, 0);

                skeleton.setAttachment("head-bb", "head");

                stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations.

                state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc).

                loadingAnimate = false;
            }
        }).start();
    }

    public abstract FileHandle getExtureFile();

    public abstract FileHandle getJsonFile();

    public abstract void initAnimationStateData(AnimationStateData stateData,AnimationState state);

    @Override
    public void resize(int width, int height) {
        camera.setToOrtho(false); // Update camera with new size.
    }

    public void setCanDraw(boolean candraw) {

        if (openDEBUGLog)
            timber.log.Timber.d("setCanDraw:"+candraw);

        m_candraw = candraw;

        if (!m_candraw) {
//			放置不可见时手动销毁的内容
            return;
        }
    }

    @Override
    public void render() {

        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        if (forceOver)
            return;

        if (!m_candraw) {
            //			放置不可见时手动销毁的内容
            return;
        }

        if (loadingAnimate)
            return;

//		放置动画逻辑
        state.update(Gdx.graphics.getDeltaTime()); // Update the animation time.

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
        skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.

        // Configure the camera, SpriteBatch, and SkeletonRendererDebug.
        camera.update();
        batch.getProjectionMatrix().set(camera.combined);
        debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined);

        batch.begin();
        renderer.draw(batch, skeleton); // Draw the skeleton images.
        batch.end();

		debugRenderer.draw(skeleton); // Draw debug lines.

    }




    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void dispose() {

        if (openDEBUGLog)
            timber.log.Timber.d("dispose");

        mBatch.dispose();

        //遍历释放所有资源
        atlas.dispose();
    }

    Vector3 point=new Vector3();

    public boolean isContainsPoint(int screenX, int screenY){
        if (!m_candraw||loadingAnimate) {
            return false;
        }
        camera.unproject(point.set(screenX, screenY, 0));
        skeletonBounds.update(skeleton, true);
        return skeletonBounds.aabbContainsPoint(point.x, point.y);
    }

    /**
     * 换装饰
     *
     * @param slotName       插槽名称
     * @param attachmentName 装饰名称
     * @return
     */
    public boolean setAttachment(String slotName, String attachmentName) {
        if (skeleton == null || TextUtils.isEmpty(slotName)) {
            return false;
        }
        Slot slot = skeleton.findSlot(slotName);
        if (slot == null) {
            return false;
        }
        if (TextUtils.isEmpty(attachmentName)) {
            slot.setAttachment(null);
        } else {
            Attachment attachment = skeleton.getAttachment(slotName, attachmentName);
            if (attachment == null) {
                return false;
            }
            skeleton.setAttachment(slotName, attachmentName);
        }
        return true;
    }

    /**
     * 卸载装饰
     *
     * @param slotName
     * @return
     */
    private boolean unsetAttachment(String slotName) {
        Slot slot = skeleton.findSlot(slotName);
        if (slot != null) {
            slot.setAttachment(null);
            return true;
        }
        return false;
    }

    /**
     * 换肤
     *
     * @param skinName 皮肤名称
     * @return
     */
    public boolean setSkin(String skinName) {
        if (skeleton == null || skeletonData == null || TextUtils.isEmpty(skinName)) {
            return false;
        }
        if (skeletonData.findSkin(skinName) == null) {
            return false;
        }
        skeleton.setSkin(skinName);
        return true;
    }
}
